﻿using DbStreamConverter.Properties;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
using System.Workflow.Activities.Rules;
using System.Workflow.Activities.Rules.Design;
using System.Workflow.ComponentModel.Serialization;
using System.Xml;
using System.Xml.Serialization;
using ViewMaker;
using ViewMaker.Core;
using ViewMaker.Core.Controls;

namespace DbStreamConverter
{
    [ViewProperty(PanelViewControl.Properties.HeaderWidth, 180)]
    public class MainVM : ViewModelBase
    {
        public string SourceConnectionString
        {
            get { return _sourceConnectionString; }
            set 
            { 
                this.SetValue("SourceConnectionString", out _sourceConnectionString, value); 
                Settings.Default.DefaultSourceConnectionString = value;
                Settings.Default.Save();
            }
        }
        private string _sourceConnectionString;

        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "DbProviders")]
        public string SourceDbProvider
        {
            get { return _sourceDbProvider; }
            set 
            { 
                this.SetValue("SourceDbProvider", out _sourceDbProvider, value); 
                Settings.Default.DefaultSourceDbProvider = value;
                Settings.Default.Save();

            }
        }
        private string _sourceDbProvider;

        public virtual string SourceSQL
        {
            get { return _sourceSQL; }
            set { SetValue("SourceSQL", out _sourceSQL, value); }
        }
        private string _sourceSQL;

        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "SourceTables")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public string SourceTable
        {
            get { return _sourceTable; }
            set { this.SetValue("SourceTable", out _sourceTable, value); }
        }
        private string _sourceTable;

        public ObservableCollection<string> SourceTables
        {
            get { return _sourceTables; }
            set { this.SetValue("SourceTables", out _sourceTables, value); }
        }
        private ObservableCollection<string> _sourceTables;    

        public string TargetConnectionString
        {
            get { return _targetConnectionString; }
            set 
            { 
                this.SetValue("TargetConnectionString", out _targetConnectionString, value); 
                Settings.Default.DefaultTargetConnectionString = value;
                Settings.Default.Save();
            }
        }
        private string _targetConnectionString;

        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "DbProviders")]
        public string TargetDbProvider
        {
            get { return _targetDbProvider; }
            set 
            { 
                this.SetValue("TargetDbProvider", out _targetDbProvider, value); 
                Settings.Default.DefaultTargetDbProvider = value;
                Settings.Default.Save();
            }
        }
        private string _targetDbProvider;

        [View(ViewControlType.ComboBox)]
        [ViewProperty(ComboBoxViewControl.Properties.ItemsSource, "TargetTables")]
        [ViewProperty(ComboBoxViewControl.Properties.IsEditable, true)]
        public string TargetTableName
        {
            get { return _targetTableName; }
            set { SetValue("TargetTableName", out _targetTableName, value); }
        }
        private string _targetTableName;

        public ObservableCollection<string> TargetTables
        {
            get { return _targetTables; }
            set { this.SetValue("TargetTables", out _targetTables, value); }
        }
        private ObservableCollection<string> _targetTables;

        public ObservableCollection<string> DbProviders { get; set; }

        public ObservableCollection<MappingVM> Mappings { get; set; }

        public MappingVM SelectedMapping
        {
            get { return _selectedMapping; }
            set { SetValue("SelectedMapping", out _selectedMapping, value); }
        }
        private MappingVM _selectedMapping;


        [Browsable(false)]
        [Display(Name="Add")]
        public ICommand AddMappingCommand { get { return CreateCommand(AddMapping, CanExecute); } }

        [Browsable(false)]
        public ICommand LoadCommand { get { return CreateCommand(Load); } }

        [Browsable(false)]
        public ICommand SaveCommand { get { return CreateCommand(Save, (x) => SelectedMapping != null && SelectedMapping.Idle); } }

        [Browsable(false)]
        public ICommand OverWriteCommand { get { return CreateCommand(OverWrite, (x) => SelectedMapping != null && SelectedMapping.Idle); } }

        [Browsable(false)]
        public ICommand ExitCommand { get { return CreateViewCommand(ViewCommands.Close); } }

        [Browsable(false)]
        public ICommand ExecuteCommand { get { return CreateCommand(Execute, (x) => SelectedMapping != null && SelectedMapping.Idle); } }

        [Browsable(false)]
        public ICommand CancelCommand { get { return CreateCommand(Cancel, (x) => SelectedMapping != null && SelectedMapping.IsBusy); } }

        [Browsable(false)]
        public ICommand EditRuleSetCommand { get { return CreateCommand(EditRuleSet, (x) => SelectedMapping != null && SelectedMapping.Idle); } }

        [Browsable(false)]
        public ICommand RemovedRuleSetCommand { get { return CreateCommand(RemoveRuleSet, (x) => SelectedMapping != null && SelectedMapping.Idle); } }

        [Browsable(false)]
        public ICommand ExportDataCommand { get { return CreateCommand(ExportData, (x) => SelectedMapping != null && SelectedMapping.Idle); } }

        [Browsable(false)]
        public ICommand DropTempTableCommand { get { return CreateCommand(DropTempTable, (x) => SelectedMapping != null && SelectedMapping.Idle && SelectedMapping.TargetTableAsTemp); } }

        [Browsable(false)]
        public ICommand CloseCommand { get { return CreateCommand(MappingClose, (x) => SelectedMapping != null && SelectedMapping.Idle); } }


        public MainVM()
        {
            try
            {
                this.Mappings = new ObservableCollection<MappingVM>();
                DbProviders = new ObservableCollection<string>();
                foreach (var prov in DbProviderRepository.ProviderList)
                {
                    DbProviders.Add(prov.Key);
                }
                this.PropertyChanged += MainVM_PropertyChanged;
                this.SourceDbProvider = Settings.Default.DefaultSourceDbProvider;
                this.TargetDbProvider = Settings.Default.DefaultTargetDbProvider;
                this.SourceConnectionString = Settings.Default.DefaultSourceConnectionString;
                this.TargetConnectionString = Settings.Default.DefaultTargetConnectionString;
                
            }
            catch (Exception ex)
            {
                this.ShowMessage(ex.Message);
            }
        }

        internal string GetSource()
        {
            if (!string.IsNullOrEmpty(SourceSQL))
            {
                return SourceSQL;
            }
            else
            {
                return SourceTable;
            }
        }


        private void AddMapping()
        {
            var newMap = new MappingVM(this);
            Mappings.Add(newMap);
            SelectedMapping = newMap;
        }
        private void MappingClose()
        {
            Mappings.Remove(SelectedMapping);
        }

        private void Execute()
        {
            if (SelectedMapping != null)
            {
                SelectedMapping.ExecuteCommand.Execute(null);
            }
        }

        private void Cancel()
        {
            if (SelectedMapping != null)
            {
                SelectedMapping.CancelCommand.Execute(null);
            }
        }

        private void EditRuleSet()
        {
            if (SelectedMapping != null)
            {
                SelectedMapping.EditRuleSetCommand.Execute(null);
            }
        }

        private void RemoveRuleSet()
        {
            if (SelectedMapping != null)
            {
                SelectedMapping.RemoveRuleSetCommand.Execute(null);
            }
        }

        private void ExportData()
        {
            if (SelectedMapping != null)
            {
                SelectedMapping.ExportDataCommand.Execute(null);
            }
        }

        private void DropTempTable()
        {
            if (SelectedMapping != null)
            {
                if (this.ShowOKCancel(string.Format("Are you sure you want to drop {0} table?", SelectedMapping.TargetTable)))
                {
                    SelectedMapping.DropTempTableCommand.Execute(null);
                }
            }
        }


        private void Load()
        {
            var dialog = new OpenFileDialog();
            dialog.Filter = "mapping|*.mapping";
            if (dialog.ShowDialog() == true)
            {
                MappingVM vm;
                using (var file = new FileStream(dialog.FileName, FileMode.Open, FileAccess.Read))
                {
                    var xmlSeri = new XmlSerializer(typeof(MappingVM));
                    vm = (MappingVM)xmlSeri.Deserialize(file);
                }
                vm.Init();
                Mappings.Add(vm);
                SelectedMapping = vm;
                vm.FileName = dialog.FileName;
            }
        }

        private void Save()
        {
            if (SelectedMapping == null) return;
            var dialog = new SaveFileDialog();
            dialog.Filter = "mapping|*.mapping";
            if (dialog.ShowDialog() == true)
            {
                using (var file = new FileStream(dialog.FileName, FileMode.Create, FileAccess.Write))
                {
                    var xmlSeri = new XmlSerializer(typeof(MappingVM));
                    xmlSeri.Serialize(file, SelectedMapping);
                    SelectedMapping.FileName = dialog.FileName;
                }
            }
        }

        private void OverWrite()
        {
            if (SelectedMapping == null) return;
            if (SelectedMapping.FileName != null)
            {
                using (var file = new FileStream(SelectedMapping.FileName, FileMode.Create, FileAccess.Write))
                {
                    var xmlSeri = new XmlSerializer(typeof(MappingVM));
                    xmlSeri.Serialize(file, SelectedMapping);
                }
            }
            else
            {
                Save();
            }
        }


        private bool CanExecute()
        {
            if (string.IsNullOrEmpty(this.TargetTableName)) return false;
            if (string.IsNullOrEmpty(this.SourceSQL) && string.IsNullOrEmpty(this.SourceTable)) return false;
            return true;
        }



        void MainVM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "SourceDbProvider" || e.PropertyName == "SourceConnectionString")
            {
                if (!string.IsNullOrEmpty(this.SourceConnectionString))
                {
                    var db = DbProviderRepository.GetDbSchemaProvider(this.SourceDbProvider, this.SourceConnectionString);
                    SourceTables = new ObservableCollection<string>(db.GetTablesViews().OrderBy(x => x));
                }
            }
            if (e.PropertyName == "TargetDbProvider" || e.PropertyName == "TargetConnectionString")
            {
                if (!string.IsNullOrEmpty(this.TargetConnectionString))
                {
                    var db = DbProviderRepository.GetDbSchemaProvider(this.TargetDbProvider, this.TargetConnectionString);
                    TargetTables = new ObservableCollection<string>(db.GetTablesViews().OrderBy(x => x));
                }
            }
        }
    }
}
